home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
intrvews
/
xgrab.lha
/
xgrab
/
grabst
/
util.c
< prev
Wrap
C/C++ Source or Header
|
1990-03-06
|
9KB
|
384 lines
/**
GRAB Graph Layout and Browser System
Copyright (c) 1986, 1988 Regents of the University of California
Copyright (c) 1989, Tera Computer Company
**/
/* util.c -- miscellaneous useful routines */
#include "attribute.h"
#include "digraph.h"
#include "debug.h"
NODE *get_next_node(), *get_prev_node();
print_levels(digraph)
DIGRAPH *digraph;
/* print_levels prints the nodes in each level of digraph. */
{
LEVEL *level; /* each level */
MEMBER *member; /* each member of each level */
printf("\n\nDigraph Levels:\n");
each_level(digraph, level)
loop
printf(" Level %d: ", Lno(level));
each_member(level, member)
loop
printf(" %s", Name(member));
printf("[%1.2f, %1.2f]", Bc(member, UP), Bc(member, DOWN));
endloop
printf("\n");
endloop
printf("\n");
} /* print_levels */
print_set(digraph, set)
DIGRAPH *digraph;
SET *set;
/* print_set prints the elements in set as nodes in digraph. */
{
VNO vno; /* each vno */
each_element(set, vno)
loop
printf(" %s", Name(Node(digraph, vno)));
endloop
} /* print_set */
PrintError(message)
char *message;
/* PrintError prints message to standard error */
{
fprintf(stderr, "\n** Error: %s\n", message);
} /* PrintError */
/**
the following four routines (get_edge, get_in_edge, num_edges, and
max_edges, are all remarkably alike. Hence, if you change one, you
probably should be changing them all.
These four routines are the best way to go from successor/ancestor
sets to outedges. It is not a good idea to use the outedge or inedge
lists of a node when accessing the displayed graph, because the outedges
and inedges are only an abstract picture of the graph. For example,
dummy and coalescer nodes have no in or out edges. The
successor/ancestor sets give a better picture of the displayed graph.
When accessing a particular edge, get_edge should be used, unless
an inedge is needed, in which case get_in_edge should be used.
The normal way to access all edges between two nodes goes something
like this:
for (i = max_edges(from, to); i > 0; i--)
{
if ((edge = get_edge(digraph, from, to, i)) != NULL)
{
foo(edge);
}
}
Note that it is necessary to check that the edge exists (i.e. check
that get_edge didn't return NULL), because the user could have deleted
an edge between two nodes. The ordinalities of edges are not
compacted (except when the graph is laid out), because that would
create an inconsistency between the digraph structure, the
data structure used by the InterViews interface, and the displayed
graph. In other words, you'd have to update two data structures and
redraw some edges when deleting an edge, which is too much work.
The drawback is the extra checking for missing edges.
if you want to check whether an edge exists between two nodes, use
num_edges. Any other uses of num_edges should be viewed with suspicion.
num_edges should *never* be used to determine the valid ordinalities
for edges between two nodes since, as I noted above, there could
be gaps in the sequence. In other words, max_edges ?= num_edges
**/
OUTEDGE *get_edge(digraph, node, tonode, ord)
register DIGRAPH *digraph;
register NODE *node, *tonode;
int ord;
/**
finds the outedge from node to tonode of
ordinality ord. Outedges only go from proper nodes (not dummy or
coalescer nodes) in the graph, so this is especially useful if either
node or tonode is a dummy or coalescer.
**/
{
VNO nvno;
register OUTEDGE *outedge;
/* if either node is a dummy, find the endpoints */
if (Is_dummy(node))
{
if ((node = get_prev_node(digraph, node)) == NULL)
{
return NULL;
}
}
if (Is_dummy(tonode))
{
if ((tonode = get_next_node(digraph, tonode)) == NULL)
{
return NULL;
}
}
/**
Ordinalities of edges from/to coalescer nodes are figured by
considering the elements in the expansion in order, with the
ordinality of an edge being the ordinality of the edge relative
to the element plus the sum of the ordinalities of edges in
previous elements. So, for example, if a coalescer node contains
A, B, and C, and A has 3 edges to D, B has 1 edge, and C has 2,
the edges from the coalescer to D are considered to have the
following ordinalities:
edges originally from A: 1-3
" " " B: 4
" " " C: 5-6
assuming vno(A) < vno(B) < vno(C)
Note that this is a recursive definition, so A, B, C, or D could be
coalescer nodes themselves.
**/
if (Coalescer(node))
{
int max;
each_element(Expansion(node), nvno)
loop
if (ord <= (max = max_edges(Node(digraph, nvno), tonode)))
{
return get_edge(digraph, Node(digraph, nvno), tonode, ord);
}
else
{
ord -= max;
}
endloop;
}
else if (Coalescer(tonode))
{
int max;
each_element(Expansion(tonode), nvno)
loop
if (ord <= (max = max_edges(node, Node(digraph, nvno))))
{
return get_edge(digraph, node, Node(digraph, nvno), ord);
}
else
{
ord -= max;
}
endloop;
}
else
{
all_out_edges(node, outedge)
loop
if (To_vno(outedge) == Vno(tonode) && Ord(outedge) == ord)
{
return outedge;
}
endloop;
}
return NULL;
}
INEDGE *get_in_edge(digraph, node, tonode, ord)
register DIGRAPH *digraph;
register NODE *node, *tonode;
int ord;
/**
finds the inedge from node to tonode of
ordinality ord. Inedges only go from proper nodes (not dummy or coalescer
nodes) in the graph, so this is especially useful if either node or tonode
is a dummy or coalescer.
**/
{
VNO nvno;
register INEDGE *inedge;
/* if either node is a dummy, find the endpoints of the edge */
if (Is_dummy(node))
{
if ((node = get_prev_node(digraph, node)) == NULL)
{
return NULL;
}
}
if (Is_dummy(tonode))
{
if ((tonode = get_next_node(digraph, tonode)) == NULL)
{
return NULL;
}
}
/**
see get_edge for an explanation of edge ordinalities for coalescer
nodes
**/
if (Coalescer(node))
{
int max;
each_element(Expansion(node), nvno)
loop
if (ord <= (max = max_edges(Node(digraph, nvno), tonode)))
{
return get_in_edge(digraph, Node(digraph, nvno), tonode, ord);
}
else
{
ord -= max;
}
endloop;
}
else if (Coalescer(tonode))
{
int max;
each_element(Expansion(tonode), nvno)
loop
if (ord <= (max = max_edges(node, Node(digraph, nvno))))
{
return get_in_edge(digraph, node, Node(digraph, nvno), ord);
}
else
{
ord -= max;
}
endloop;
}
else
{
all_in_edges(tonode, inedge)
loop
if (From_vno(inedge) == Vno(node) && Ord(inedge) == ord)
{
return inedge;
}
endloop;
}
return NULL;
}
num_edges(from, to)
NODE* from;
NODE* to;
/* finds the number of edges from from_node to to_node */
{
VNO nvno;
OUTEDGE *outedge;
int count = 0;
if (Is_dummy(from))
{
if ((from = get_prev_node(digraph, from)) == NULL)
{
return 0;
}
}
if (Is_dummy(to))
{
if ((to = get_next_node(digraph, to)) == NULL)
{
return 0;
}
}
if (Coalescer(from))
{
each_element(Expansion(from), nvno)
loop
count += num_edges(Node(digraph, nvno), to);
endloop;
}
else if (Coalescer(to))
{
each_element(Expansion(to), nvno)
loop
count += num_edges(from, Node(digraph, nvno));
endloop;
}
else
{
all_out_edges(from, outedge)
loop
if (To_vno(outedge) == Vno(to))
{
count++;
}
endloop;
}
return count;
}
max_edges(from, to)
NODE* from;
NODE* to;
/**
finds the maximum value for ordinality in an edge from from_node to
to_node
**/
{
VNO nvno;
OUTEDGE *outedge;
int max = 0;
if (Is_dummy(from))
{
if ((from = get_prev_node(digraph, from)) == NULL)
{
return 0;
}
}
if (Is_dummy(to))
{
if ((to = get_next_node(digraph, to)) == NULL)
{
return 0;
}
}
if (Coalescer(from))
{
each_element(Expansion(from), nvno)
loop
max += max_edges(Node(digraph, nvno), to);
endloop;
}
else if (Coalescer(to))
{
each_element(Expansion(to), nvno)
loop
max += max_edges(from, Node(digraph, nvno));
endloop;
}
else
{
all_out_edges(from, outedge)
loop
if (To_vno(outedge) == Vno(to))
{
max = MAX(max, Ord(outedge));
}
endloop;
}
return max;
}